using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using System;
using Microsoft.Xna.Framework.Content;
using System.Collections.Generic;
using BikyBall.Object;
using System.Linq;
using System.Text;
using BikyBall.Graphic;

namespace BikyBall
{
    static class MapConstructor
    {
        public static GraphicProperty Construct(Map map)
        {

            GraphicProperty gp = new GraphicProperty();
            SetNbVerticesTrianglesIndices(map, gp);

            gp.Vertices = new VertexPositionNormalTexture[gp.NumVertices];
            gp.Indices = new short[gp.NumIndices];
            Vector3 btmLeftFront = new Vector3(0.0f, 0.0f, 0.0f);
            Vector3 btmLeftBack = new Vector3(0.0f, 0.0f, 1.0f);
            Vector3 btmRightFront = new Vector3(1.0f, 0.0f, 0.0f);
            Vector3 btmRightBack = new Vector3(1.0f, 0.0f, 1.0f);
            Vector3 topLeftFront = new Vector3(0.0f, 1.0f, 0.0f);
            Vector3 topLeftBack = new Vector3(0.0f, 1.0f, 1.0f);
            Vector3 topRightFront = new Vector3(1.0f, 1.0f, 0.0f);
            Vector3 topRightBack = new Vector3(1.0f, 1.0f, 1.0f);
            Vector3 normalBottom = new Vector3(0.0f, -1.0f, 0.0f);
            Vector3 normalTop = new Vector3(0.0f, -1.0f, 0.0f);

            // UV texture coordinates
            Vector2 textureTopLeft = new Vector2(0.0f, 0.0f);
            Vector2 textureTopRight = new Vector2(1.0f / 4.0f, 0.0f);
            Vector2 textureBottomLeft = new Vector2(0.0f, 1.0f / 4.0f);
            Vector2 textureBottomRight = new Vector2(1.0f / 4.0f, 1.0f / 4.0f);

            short i = 0;
            short v = 0;
            for (int x = 0; x < map.SizeX; x++)
            {
                for (int y = 0; y < map.SizeY; y++)
                {
                    for (int z = 0; z < map.SizeZ; z++)
                    {
                        // Add the _vertices for a face. 
                        Vector2 shiftTexture = new Vector2((float)((int)map.MapCases[x, y, z] % 4) / 4.0f, ((int)map.MapCases[x, y, z] / 4) / 4.0f);
                        Vector3 shiftPos = new Vector3(x, y, z);
                        switch (map.MapCases[x,y,z])
                        {
                            case MapCase.EMPTY_CASE:
                                break;
                            case MapCase.WALL_CASE:
                                gp.Vertices[v] = new VertexPositionNormalTexture(btmRightFront + shiftPos, normalBottom, textureBottomLeft + shiftTexture);
                                gp.Vertices[v + 1] = new VertexPositionNormalTexture(topRightFront + shiftPos, normalTop, textureTopLeft + shiftTexture);
                                gp.Vertices[v + 2] = new VertexPositionNormalTexture(btmRightBack + shiftPos, normalBottom, textureBottomRight + shiftTexture);
                                gp.Vertices[v + 3] = new VertexPositionNormalTexture(topRightBack + shiftPos, normalTop, textureTopRight + shiftTexture);
                                gp.Vertices[v + 4] = new VertexPositionNormalTexture(btmLeftBack + shiftPos, normalBottom, textureBottomLeft + shiftTexture);
                                gp.Vertices[v + 5] = new VertexPositionNormalTexture(btmLeftFront + shiftPos, normalBottom, textureBottomRight + shiftTexture);
                                gp.Vertices[v + 6] = new VertexPositionNormalTexture(topLeftBack + shiftPos, normalTop, textureTopLeft + shiftTexture);
                                gp.Vertices[v + 7] = new VertexPositionNormalTexture(topLeftFront + shiftPos, normalTop, textureTopRight + shiftTexture);
                                // Face Devant
                                gp.Indices[i] = (short)(v + 4); gp.Indices[i + 1] = (short)(v + 6); gp.Indices[i + 2] = (short)(v + 2);
                                gp.Indices[i + 3] = (short)(v + 3); gp.Indices[i + 4] = (short)(v + 2); gp.Indices[i + 5] = (short)(v + 6);
                                // Face Derriere
                                gp.Indices[i + 6] = (short)(v + 7); gp.Indices[i + 7] = (short)(v + 5); gp.Indices[i + 8] = (short)(v);
                                gp.Indices[i + 9] = (short)(v + 7); gp.Indices[i + 10] = (short)(v); gp.Indices[i + 11] = (short)(v + 1);
                                // Face Gauche
                                gp.Indices[i + 12] = (short)(v + 5); gp.Indices[i + 13] = (short)(v + 6); gp.Indices[i + 14] = (short)(v + 4);
                                gp.Indices[i + 15] = (short)(v + 6); gp.Indices[i + 16] = (short)(v + 5); gp.Indices[i + 17] = (short)(v + 7);
                                // Face Droite
                                gp.Indices[i + 18] = (short)(v); gp.Indices[i + 19] = (short)(v + 2); gp.Indices[i + 20] = (short)(v + 3);
                                gp.Indices[i + 21] = (short)(v + 1); gp.Indices[i + 22] = (short)(v); gp.Indices[i + 23] = (short)(v + 3);
                                i += 24;
                                v += 8;
                                break;
                            default:
                                gp.Vertices[v] = new VertexPositionNormalTexture(btmRightBack + shiftPos, normalBottom, textureBottomRight + shiftTexture);
                                gp.Vertices[v + 1] = new VertexPositionNormalTexture(btmLeftBack + shiftPos, normalBottom, textureBottomLeft + shiftTexture);
                                gp.Vertices[v + 2] = new VertexPositionNormalTexture(btmLeftFront + shiftPos, normalBottom, textureTopLeft + shiftTexture);
                                gp.Vertices[v + 3] = new VertexPositionNormalTexture(btmRightFront + shiftPos, normalBottom, textureTopRight + shiftTexture);
                                gp.Indices[i] = v; gp.Indices[i + 1] = (short)(v + 1); gp.Indices[i + 2] = (short)(v + 2);
                                gp.Indices[i + 3] = (short)(v + 3); gp.Indices[i + 4] = v; gp.Indices[i + 5] = (short)(v + 2);
                                //gp.Vertices[i + 4] = new VertexPositionNormalTexture(btmRightBack + shiftPos, normalBottom, textureBottomRight + shiftTexture);
                                //gp.Vertices[i + 5] = new VertexPositionNormalTexture(btmLeftFront + shiftPos, normalBottom, textureTopLeft + shiftTexture);
                                i += 6;
                                v += 4;
                                break;
                        }
                    }
                }
            }
            gp.VertexBuffer = new VertexBuffer(GraphicEngine.Device, VertexPositionNormalTexture.VertexDeclaration, gp.NumVertices, BufferUsage.WriteOnly);
            gp.VertexBuffer.SetData(gp.Vertices);
            gp.IndexBuffer = new IndexBuffer(GraphicEngine.Device, IndexElementSize.SixteenBits, gp.NumIndices, BufferUsage.WriteOnly);
            gp.IndexBuffer.SetData(gp.Indices);
            gp.Texture = GraphicEngine.Content.Load<Texture2D>("default_case");

            gp.PrimitiveType = PrimitiveType.TriangleList;
            gp.Effect = new BasicEffect(GraphicEngine.Device);
            gp.Effect.TextureEnabled = true;
            gp.Effect.Texture = gp.Texture;
            return gp;
        }

        private static void SetNbVerticesTrianglesIndices(Map map, GraphicProperty gp)
        {
            int vertices = 0;
            int triangles = 0;
            int indices = 0;
            for (int x = 0; x < map.SizeX; x++)
            {
                for (int y = 0; y < map.SizeY; y++)
                {
                    for (int z = 0; z < map.SizeZ; z++)
                    {
                        switch (map.MapCases[x, y, z])
                        {
                            case MapCase.EMPTY_CASE:
                                break;
                            case MapCase.WALL_CASE:
                                vertices += 8;
                                triangles += 8;
                                indices += 24;
                                break;
                            default:
                                vertices += 4;
                                triangles += 2;
                                indices += 6;
                                break;
                        }
                    }
                }
            }
            gp.NumIndices = indices;
            gp.NumTriangles = triangles;
            gp.NumVertices = vertices;
        }
    }
}
